#include "process.h"
#include "pmm.h"
#include "printf.h"
#include "riscv.h"
#include "clint.h"
#include <stddef.h>

// 进程表
static proc_t proc_table[MAX_PROC];

// 当前运行进程
static proc_t* current_proc = NULL;

// 就绪队列头指针
static proc_t* ready_queue = NULL;

// 下一个可用PID
static int next_pid = 1;

// 简单的字符串复制函数
static void my_strncpy(char* dest, const char* src, size_t n) {
    size_t i;
    for (i = 0; i < n - 1 && src[i] != '\0'; i++) {
        dest[i] = src[i];
    }
    dest[i] = '\0';
}

// 简单的内存清零函数
static void my_memset(void* s, int c, size_t n) {
    unsigned char* p = (unsigned char*)s;
    for (size_t i = 0; i < n; i++) {
        p[i] = (unsigned char)c;
    }
}

/**
 * 初始化进程管理系统
 */
void process_init(void) {
    printf("\n=== 进程管理系统初始化 ===\n");
    
    // 清空进程表
    for (int i = 0; i < MAX_PROC; i++) {
        proc_table[i].state = PROC_UNUSED;
        proc_table[i].pid = 0;
        proc_table[i].next = NULL;
    }
    
    current_proc = NULL;
    ready_queue = NULL;
    next_pid = 1;
    
    printf("进程表大小: %d\n", MAX_PROC);
    printf("内核栈大小: %d bytes\n", STACK_SIZE);
    printf("=== 进程管理系统初始化完成 ===\n");
}

/**
 * 分配进程结构
 */
proc_t* alloc_process(void) {
    // 在进程表中查找空闲槽
    for (int i = 0; i < MAX_PROC; i++) {
        if (proc_table[i].state == PROC_UNUSED) {
            proc_t* p = &proc_table[i];
            
            // 初始化进程结构
            my_memset(p, 0, sizeof(proc_t));
            p->pid = next_pid++;
            p->state = PROC_EMBRYO;
            p->time_slice = 50;  // 默认50ms时间片
            
            // 分配内核栈
            p->stack = alloc_pages(1);  // 分配一个页作为栈
            if (!p->stack) {
                p->state = PROC_UNUSED;
                printf("[错误] 分配进程栈失败\n");
                return NULL;
            }
            
            printf("[进程] 分配进程: PID=%d, 栈=%p\n", p->pid, p->stack);
            return p;
        }
    }
    
    printf("[错误] 进程表已满\n");
    return NULL;
}

/**
 * 释放进程资源
 */
void free_process(proc_t* p) {
    if (!p) return;
    
    printf("[进程] 释放进程: PID=%d\n", p->pid);
    
    // 释放内核栈
    if (p->stack) {
        free_pages(p->stack, 1);
        p->stack = NULL;
    }
    
    // 标记为未使用
    p->state = PROC_UNUSED;
    p->pid = 0;
}

/**
 * 将进程加入就绪队列
 */
static void enqueue_ready(proc_t* p) {
    p->next = NULL;
    
    if (!ready_queue) {
        ready_queue = p;
    } else {
        proc_t* tail = ready_queue;
        while (tail->next) {
            tail = tail->next;
        }
        tail->next = p;
    }
}

/**
 * 从就绪队列取出进程
 */
static proc_t* dequeue_ready(void) {
    if (!ready_queue) {
        return NULL;
    }
    
    proc_t* p = ready_queue;
    ready_queue = ready_queue->next;
    p->next = NULL;
    
    return p;
}

/**
 * 创建新进程
 */
int create_process(void (*entry)(void)) {
    if (!entry) {
        printf("[错误] 进程入口函数为空\n");
        return -1;
    }
    
    // 分配进程结构
    proc_t* p = alloc_process();
    if (!p) {
        return -1;
    }
    
    // 设置进程属性
    p->entry = entry;
    p->parent = current_proc;
    p->create_time = get_time();
    my_strncpy(p->name, "process", sizeof(p->name));
    
    // 设置为就绪态并加入队列
    p->state = PROC_RUNNABLE;
    enqueue_ready(p);
    
    printf("[进程] 创建进程成功: PID=%d\n", p->pid);
    return p->pid;
}

/**
 * 终止当前进程
 */
void exit_process(int status) {
    if (!current_proc) {
        printf("[错误] 没有当前进程\n");
        return;
    }
    
    printf("[进程] 进程退出: PID=%d, 状态=%d\n", current_proc->pid, status);
    
    current_proc->exit_status = status;
    current_proc->state = PROC_ZOMBIE;
    
    // 唤醒父进程(如果父进程在等待)
    if (current_proc->parent && current_proc->parent->state == PROC_SLEEPING) {
        current_proc->parent->state = PROC_RUNNABLE;
        enqueue_ready(current_proc->parent);
    }
    
    // 触发调度,切换到其他进程
    schedule_process();
}

/**
 * 等待子进程结束
 */
int wait_process(int* status) {
    if (!current_proc) {
        return -1;
    }
    
    // 查找僵尸子进程
    for (int i = 0; i < MAX_PROC; i++) {
        proc_t* p = &proc_table[i];
        if (p->state == PROC_ZOMBIE && p->parent == current_proc) {
            // 找到僵尸子进程
            int pid = p->pid;
            if (status) {
                *status = p->exit_status;
            }
            
            printf("[进程] 回收子进程: PID=%d\n", pid);
            free_process(p);
            return pid;
        }
    }
    
    // 没有僵尸子进程,进入睡眠等待
    printf("[进程] PID=%d 等待子进程...\n", current_proc->pid);
    current_proc->state = PROC_SLEEPING;
    schedule_process();
    
    return -1;
}

/**
 * 获取当前进程
 */
proc_t* get_current_process(void) {
    return current_proc;
}

/**
 * 进程调度(简单轮转调度)
 */
void schedule_process(void) {
    // 如果当前进程还能继续运行,放回队尾
    if (current_proc && current_proc->state == PROC_RUNNING) {
        current_proc->state = PROC_RUNNABLE;
        enqueue_ready(current_proc);
    }
    
    // 取出下一个就绪进程
    proc_t* next = dequeue_ready();
    if (next) {
        current_proc = next;
        current_proc->state = PROC_RUNNING;
        current_proc->elapsed_time = 0;
        
        printf("[调度] 切换到进程: PID=%d (%s)\n", current_proc->pid, current_proc->name);
        
        // 这里应该进行上下文切换,简化版本直接调用entry
        if (current_proc->entry) {
            current_proc->entry();
        }
    } else {
        current_proc = NULL;
        printf("[调度] 无就绪进程\n");
    }
}

/**
 * 打印所有进程状态
 */
void print_processes(void) {
    printf("\n=== 进程列表 ===\n");
    printf("PID  状态       名称           父进程\n");
    printf("----------------------------------------\n");
    
    for (int i = 0; i < MAX_PROC; i++) {
        proc_t* p = &proc_table[i];
        if (p->state != PROC_UNUSED) {
            const char* state_str;
            switch (p->state) {
                case PROC_EMBRYO:   state_str = "创建中"; break;
                case PROC_SLEEPING: state_str = "睡眠"; break;
                case PROC_RUNNABLE: state_str = "就绪"; break;
                case PROC_RUNNING:  state_str = "运行"; break;
                case PROC_ZOMBIE:   state_str = "僵尸"; break;
                default:            state_str = "未知"; break;
            }
            
            printf("%-4d %-10s %-14s %d\n",
                   p->pid, state_str, p->name,
                   p->parent ? p->parent->pid : 0);
        }
    }
    printf("========================================\n\n");
}

